#ifndef __BS_FATFS__
#define __BS_FATFS__	0x007E

#include "bs_app.h"
#include "integer.h"	/* Basic integer types */

/* Definitions corresponds to multi partition */
#define _DRIVES		                      2

#define	_MAX_SS		                      4096
/* Definitions corresponds to multiple sector size */

#define	SS(fs)	                          (_MAX_SS)

#define LD2PD(drv)                        (drv)	/* Physical drive# is equal to the logical drive# */

#define _FS_READONLY                       0


/* File system object structure */

typedef struct _FATFS_ {
	BYTE	fs_type;                      /* FAT sub type */
	BYTE	drive;                        /* Physical drive number */
	BYTE	csize;                        /* Number of sectors per cluster */
	BYTE	n_fats;                       /* Number of FAT copies */
	BYTE	wflag;	                      /* win[] dirty flag (1:must be written back) */
	BYTE	fsi_flag;                     /* fsinfo dirty flag (1:must be written back) */
	WORD	n_rootdir;                    /* Number of root directory entries (0 on FAT32) */
#if _FS_REENTRANT
	_SYNC_t	sobj;		/* Identifier of sync object */
#endif
	// DWORD	last_clust;	/* Last allocated cluster */
	// DWORD	free_clust;	/* Number of free clusters */
	// DWORD	fsi_sector;	/* fsinfo sector */
	DWORD	sects_fat;                    /* Sectors per fat */
	DWORD	max_clust;	                  /* Maximum cluster# + 1. Number of clusters is max_clust - 2 */
	DWORD	fatbase;	                  /* FAT start sector */
	DWORD	dirbase;	                  /* Root directory start sector (Cluster# on FAT32) */
	DWORD	database;	                  /* Data start sector */
	DWORD	winsect;	                  /* Current sector appearing in the win[] */
	BYTE	win[_MAX_SS];                 /* Disk access window for Directory/FAT */
} FATFS;


/* Directory object structure */

typedef struct _DIR_ {
    FATFS*    fs;                         /* Pointer to the owner file system object */
    WORD      index;                      /* Current read/write index number */
    DWORD     sect;                       /* Current sector */
    BYTE      *dir;                       /* Pointer to the current SFN entry in the win[] */
    BYTE*     fn;                         /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
} DIR;


typedef struct _FIL_ {
    FATFS*    fs;                         /* Pointer to the owner file system object */
    WORD      flag;                       /* File status flags */
    BYTE      csect;                      /* Sector address in the cluster */
    DWORD     fptr;                       /* File R/W pointer */
    DWORD     fsize;                      /* File size */
    DWORD     org_clust;                  /* File start cluster */
    DWORD     curr_clust;                 /* Current cluster */
    DWORD     dsect;                      /* Current data sector */
    DWORD     dir_sect;                   /* Sector containing the directory entry */
    BYTE*     dir_ptr;                    /* Pointer to the directory entry in the window */
    BYTE      buf[_MAX_SS];               /* File R/W buffer */
} FIL;


/* File status structure */

typedef struct _FILINFO_ {
	DWORD	fsize;		                  /* File size */
	WORD	fdate;		                  /* Last modified date */
	WORD	ftime;		                  /* Last modified time */
	BYTE	fattrib;	                  /* Attribute */
	char	fname[13];	                  /* Short file name (8.3 format) */
} FILINFO;


/* journal file structure */
// 当前扇区：相对值
// 起始扇区：绝对值
// 当前指针
// 最大扇区：相对值
typedef struct _JF_FILE {
    uint32_t	fptr;		                  /* File size */
    uint32_t	ofs_sect;		                  /* Last modified date */
    uint32_t    bmp_base;   	                  /* Short file name (8.3 format) */
    uint32_t	first_sect;                     /* Last modified time */
    uint32_t	last_sect;	                  /* Attribute */

    uint32_t    flag;
    uint8_t     buf[256];
} JF_FILE;


/* File function return code (FRESULT) */

typedef enum {
	FR_OK = 0,		             /* 0 */
	FR_DISK_ERR,	             /* 1 */
	FR_INT_ERR,		             /* 2 */
	FR_NOT_READY,	             /* 3 */
	FR_NO_FILE,		             /* 4 */
	FR_NO_PATH,		             /* 5 */
	FR_INVALID_NAME,             /* 6 */
	FR_DENIED,		             /* 7 */
	FR_EXIST,		             /* 8 */
	FR_INVALID_OBJECT,           /* 9 */
	FR_WRITE_PROTECTED,          /* 10 */
	FR_INVALID_DRIVE,            /* 11 */
	FR_NOT_ENABLED,	             /* 12 */
	FR_NO_FILESYSTEM,            /* 13 */
	FR_MKFS_ABORTED,             /* 14 */
	FR_TIMEOUT		             /* 15 */
} FRESULT;



/*--------------------------------------------------------------*/
/* FatFs module application interface                           */

FRESULT f_mount (BYTE, FATFS*);						/* Mount/Unmount a logical drive */
FRESULT f_open (FIL*, const CHAR*, WORD);			/* Open or create a file */
FRESULT f_read (FIL*, void*, UINT, UINT*);			/* Read data from a file */
FRESULT f_write (FIL*, const void*, UINT, UINT*);	/* Write data to a file */
FRESULT f_lseek (FIL*, DWORD);						/* Move file pointer of a file object */
FRESULT f_close (FIL*);								/* Close an open file object */
FRESULT f_opendir (DIR*, const CHAR*);				/* Open an existing directory */
FRESULT f_readdir (DIR*, FILINFO*);					/* Read a directory item */
FRESULT f_stat (const CHAR*, FILINFO*);			    /* Get file status */
FRESULT f_getfree (const CHAR*, DWORD*);	        /* Get number of free clusters on the drive */
FRESULT f_truncate (FIL*);							/* Truncate file */
FRESULT f_sync (FIL*);								/* Flush cached data of a writing file */
FRESULT f_unlink (const CHAR*);					    /* Delete an existing file or directory */
FRESULT	f_mkdir (const CHAR*);						/* Create a new directory */
FRESULT f_chmod (const CHAR*, BYTE, BYTE);			/* Change attribute of the file/dir */
FRESULT f_utime (const CHAR*, const FILINFO*);		/* Change time-stamp of the file/dir */
FRESULT f_rename (const CHAR*, const CHAR*);		/* Rename/Move a file or directory */
FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*);	/* Forward data to the stream */
FRESULT f_mkfs (BYTE);					/* Create a file system on the drive */
FRESULT f_chdir (const CHAR*);						/* Change current directory */
FRESULT f_chdrive (BYTE);							/* Change current drive */
FRESULT f_open_by_index (FIL*, BYTE, WORD);
FRESULT f_create_by_index (FIL *fp, BYTE index, CHAR *dent, WORD guid);
FRESULT f_unlink_by_index (BYTE, BYTE);
#if _USE_STRFUNC
int f_putc (int, FIL*);								/* Put a character to the file */
int f_puts (const char*, FIL*);						/* Put a string to the file */
int f_printf (FIL*, const char*, ...);				/* Put a formatted string to the file */
char* f_gets (char*, int, FIL*);					/* Get a string from the file */
#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
#ifndef EOF
#define EOF -1
#endif
#endif
FRESULT jf_write(const void *buff, uint32_t btw);


/*--------------------------------------------------------------*/
/* User defined functions                                       */

/* Real time clock */
#if !_FS_READONLY
DWORD get_fattime (void);	/* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
							/* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
#endif


/*--------------------------------------------------------------*/
/* Flags and offset address                                     */


/* File access control and file status flags (FIL.flag) */

#define	FA_READ				0x01
#define	FA_OPEN_EXISTING	0x00
#if _FS_READONLY == 0
#define	FA_WRITE			0x02
#define	FA_CREATE_NEW		0x04
#define	FA_CREATE_ALWAYS	0x08
#define	FA_OPEN_ALWAYS		0x10
#define FA__WRITTEN			0x20
#define FA__DIRTY			0x40
#endif
#define FA__ERROR			0x80
#define FA_EMPTY_ROOT       0x100


/* FAT sub type (FATFS.fs_type) */

#define FS_FAT12	1
#define FS_FAT16	2
#define FS_FAT32	3


/* File attribute bits for directory entry */

#define	AM_RDO	0x01	/* Read only */
#define	AM_HID	0x02	/* Hidden */
#define	AM_SYS	0x04	/* System */
#define	AM_VOL	0x08	/* Volume label */
#define AM_LFN	0x0F	/* LFN entry */
#define AM_DIR	0x10	/* Directory */
#define AM_ARC	0x20	/* Archive */
#define AM_MASK	0x3F	/* Mask of defined bits */


/* FatFs refers the FAT structure as simple byte array */
#define BPB_FS_TAG          "BS images"
#define BPB_SYS_TAG			0
#define BPB_SYS_VER     	10
#define BPB_SYS_KPerClus    11
#define BPB_SYS_TotSec      16
#define BPB_SYS_RootEntCnt  20

#define BPB_SYS_UsedSec     24
#define BPB_SYS_JnInfo      28
#define BPB_SYS_JnData      32

#define	DIR_Name			0
#define DIR_FstClust        12
#define DIR_TotClust        14
#define DIR_FileSize        16
#define DIR_UID             20

// #define	DIR_Attr			11
// #define	DIR_CrtTime			14
// #define	DIR_CrtDate			16
// #define	DIR_WrtTime			22
// #define	DIR_WrtDate			24


/*--------------------------------*/
/* Multi-byte word access macros  */
#define LD_WORD(ptr)        (WORD)(*(WORD*)(BYTE*)(ptr))
#define LD_DWORD(ptr)        (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val)    *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val)    *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)


/*--------------------------------*/
/* FAT entry access macros  */
#define NEXT_CLST(d)           (((UINT)(d)>>16)&0xFFFF)
#define PREV_CLST(d)           ((d)&0xFFFF)
#define NEW_CLST(p, n)         ((p) | ((UINT)(n)<<16))

#endif
